<?php

declare(strict_types=1);

namespace app\sys\controller;

use Ip2Region;
use think\admin\Controller;
use app\sys\service\LoginService;
use think\admin\Exception;
use think\admin\extend\CodeExtend;
use think\admin\extend\JwtExtend;
use think\admin\model\SysUser;
use think\admin\service\AdminService;
use think\admin\service\CaptchaService;
use think\admin\service\SmsService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 用户登录注册接口
 * Class B
 * @package app\sys\controller
 */
class B extends Controller
{
    /**
     * 生成验证码(code)
     * @return void
     */
    public function captchaCode()
    {
        $input = $this->_vali([
            'type.require'  => '类型不能为空!',
            'token.require' => '标识不能为空!',
        ]);
        $image = CaptchaService::instance()->initialize();
        $captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
        // 从缓存中获取验证码
        $storedToken = $this->app->cache->get($input['type'] . $input['token']);

        if ($storedToken && $storedToken === $input['token']) {
            $captcha['code'] = $image->getCode();
            // 验证成功，清除缓存
            $this->app->cache->delete($input['type'] . $input['token']);
            $this->success('验证成功', $captcha);
        } else {
            $this->error('验证已过期');
        }
    }

    /**
     * 获取验证码token
     * @return void
     */
    public function getCaptchaToken()
    {
        $captchaType = 'MobileLoginCaptcha';
        $captchaToken = CodeExtend::uniqidDate(18);
        $this->app->cache->set($captchaType . $captchaToken, $captchaToken, 360);
        $this->success('获取成功', $captchaToken);
    }
    /**
     * 获取图形验证码
     * @return void
     */
    public function getPicCaptcha()
    {
        $image = CaptchaService::instance()->initialize();
        $captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
        $this->success('生成验证码成功', $captcha);
    }

    /**
     * 验证验证码
     * @return void
     * @throws Exception
     */
    public function getPhoneValidCode()
    {
        $data = $this->_vali([
            'phone.mobile' => '手机号格式错误！',
            'phone.require' => '手机号不能为空！',
            'verify.require' => '图形验证码不能为空!',
            'uniqid.require' => '图形验证标识不能为空!',
            'action.require' => '请求方法不能为空'
        ]);

        if (!CaptchaService::instance()->check($data['verify'], $data['uniqid'])) {
            $this->error('图形验证码验证失败，请重新输入!');
        }
        $map = ['phone' => $data['phone'], 'is_deleted' => 0];
        $user = SysUser::mk()->where($map)->findOrEmpty();
        if ($data['action'] !== null) {
            if ($user->isEmpty() && in_array($data['action'], ['login', 'recover'], true)) {
                $this->error('手机号不存在!');
            }
            if (!$user->isEmpty() && $data['action'] === 'register') {
                $this->error('手机号已被注册!');
            }
            if (!in_array($data['action'], ['login', 'recover', 'register'], true)) {
                $this->error('未知请求来源!');
            }
        } else {
            $this->error('未知错误!');
        }
        [$state, $message, $data] = SmsService::instance()->sendVerifyCode($data['phone']);
        $state ? $this->success($message, $data) : $this->error($message, $data);
    }

    /**
     * 账号密码登录
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function doLogin()
    {
        $data = $this->_vali([
            'account.require' => '登录账号不能为空!',
            'account.min:4' => '登录账号不能少于5位字符!',
            'password.require' => '登录密码不能为空!',
            'password.min:4' => '登录密码不能少于6位字符!',
            'verify.require' => '图形验证码不能为空!',
            'uniqid.require' => '图形验证标识不能为空!'
        ]);
        if (!CaptchaService::instance()->check($data['verify'], $data['uniqid'])) {
            $this->error('图形验证码验证失败，请重新输入!');
        }
        /*! 用户信息验证 */
        $user = SysUser::mk()
            ->where(['is_deleted' => 0])
            ->whereRaw("BINARY `account`= ?", [$data['account']])
            //->whereRaw("BINARY `account`='{$data['account']}'") //用户名区分大小写
            ->field('account,avatar,create_time,email,id,name, phone,status, password, is_deleted')
            ->findOrEmpty();
        if ($user->isEmpty()) {
            $this->error('登录账号或密码错误，请重新输入!');
        }
        if (md5("{$user['password']}{$data['uniqid']}") != $data['password']) {
            $this->error('密码错误，请重新输入!');
        }
        $this->loginWrite($user);
    }

    /**
     * APP扫码确认登录
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function oauthLogin()
    {
        $data = $this->_vali([
            'code.require' => '授权号不能为空'
        ]);
        if(LoginService::oauthApp(LoginService::gauth($data['code']))){
            $this->success('授权成功');
        }else{
            $this->error('授权失败');
        }
    }

    /**
     * 多种登录后写入信息
     * @param $user
     * @param string $type
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function loginWrite($user, string $type = 'web'): void
    {
        $region = new Ip2Region();
        try {
            $user->inc('login_num')->save([
                'latest_login_time' => date('Y-m-d H:i:s'),
                'latest_login_ip' => $this->app->request->ip(),
                'latest_login_device' => $type,
                'latest_login_address' => $region->simple($this->app->request->ip())
            ]);
        } catch (\Exception $e) {
        }
        $user->hidden(['sort', 'status', 'password', 'is_deleted']);
        $this->app->session->set('user', $user->toArray());
        // 检测账户类型如是商户型账户必须要分配租户号（用户前台自助注册流程应为：注册账号同时生成租户号，并写入用户与租户关系关联表，写入用户角色关联表）
        $userType = AdminService::userType();
        if($userType === 'BIZ' && AdminService::getMerchantId() === '-1') $this->error('你的用户类型暂未分配账户，请联系管理员。');
        if($userType === '' || AdminService::getAdminType($userType) <= 0) $this->error('你的账号暂未分配用户类型，请联系管理员。');
        $payload['data'] = ['id' => $user['id'], 'account' => $user['account']];
        // 刷新用户权限
        AdminService::apply(true);
        sysoplog('系统用户登录', '登录系统后台成功');
        $this->success('登录成功！', JwtExtend::authorizations($payload));
    }

    /**
     * 手机号登录
     * @return void
     * @throws Exception
     * @throws DbException
     */
    public function doLoginByPhone()
    {
        $data = $this->_vali([
            'phone.mobile' => '手机号格式错误！',
            'phone.require' => '手机号不能为空！',
            'captcha.require' => '验证码不能为空!'
        ]);
        if (!SmsService::instance()->checkVerifyCode($data['captcha'], $data['phone'])) {
            $this->error('手机短信验证失败！');
        }
        $map = ['phone' => $data['phone'], 'is_deleted' => 0];
        $user = SysUser::mk()
            ->where($map)
            ->field('account,avatar,create_time,email,id,name,phone,status,password,is_deleted')
            ->findOrEmpty();
        if ($user->isEmpty()) {
            $this->error('登录错误，请重重试!');
        }
        $this->loginWrite($user);
    }

    /**
     * 登出
     * @return void
     */
    public function doLogout()
    {
        $this->app->session->destroy();
        $this->success('退出登录成功!');
    }

    /**
     * 登录获取用户
     * @login true
     * @return void
     */
    public function getLoginUser()
    {
        $this->success('获取成功！', AdminService::getUser());
    }
}